import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

class listen extends Thread{
	
	DatagramSocket clientSocket;
	int peerPort;
	String drop;
	int determin;
	float prob;
	
	public listen(DatagramSocket clientSocket, int peerPort, String drop, String s) throws SocketException{
		
		if(drop.equals("-p")){
			this.prob = Float.parseFloat(s);
		}
		else{
			this.determin = Integer.parseInt(s);
		}
		
		this.drop = drop;
		this.clientSocket=clientSocket;
		this.peerPort = peerPort;
		start();
	}
	
	public void run(){
		
		while(true){
			byte[] receiveData = new byte[1024];
			DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
			try {
				clientSocket.receive(receivePacket);
			}
			catch (IOException e1) {
				e1.printStackTrace();	
			}
			
			receiveData = receivePacket.getData();
			
			int num = (int)(((receiveData[0] & 0xFF) << 24)
					       |((receiveData[1] & 0xFF) << 16)
					       |((receiveData[2] & 0xFF) << 8)
					       |((receiveData[3] & 0xFF)));
			
			char c = (char)(((receiveData[4] & 0xFF) << 8)
							|(receiveData[5] & 0xFF));
			
			
			if (drop.equals("-p")){
				double p = Math.random();
				if(p < prob){
					isDiscard = true;
				}
				else{
					isDiscard = false;
				}
			}
			else{
				if(packetCounter%determin == 0){
					isDiscard = true;
				}
				else{
					isDiscard = false;
				}
			}
			
			boolean isData = (receivePacket.getLength()==6);
			
			if(!isDiscard){
			
				if(isData){

					System.out.println(gbnnode.currentTime()+"Packet"+num+" "+c+" received");
						
					if(num == expectedSeq){
						try {
							sendACK(num);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					
					else if (expectedSeq == 0){
					}
						
					else{
						int inOderHighest = expectedSeq-1;
						try {
							sendACK(inOderHighest);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				
				else{
					System.out.println(gbnnode.currentTime()+"ACK"+num+" received, window moves to "+ ++num);
					
					if(gbnnode.base!= num){
                        gbnnode.base = num;
                        if(gbnnode.base != gbnnode.nextPacketToSend){
                        	new timer(gbnnode.base);
                        }
                }
					
				}
			}
			
			else{
				String s = isData?"Packet":"ACK";
				System.out.println(gbnnode.currentTime()+s+num+" discarded");
			}
			
			packetCounter++;
		}
	}

	private void sendACK(int n) throws IOException {
		
		byte[] sendData = new byte[4];
		sendData[3] = (byte)(n & 0xff);
		sendData[2] = (byte)(n >> 8 & 0xff);
		sendData[1] = (byte)(n >> 16 & 0xff);
		sendData[0] = (byte)(n >> 24 & 0xff);
		
		DatagramPacket SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), peerPort);
		clientSocket.send(SendPacket);
		System.out.println(gbnnode.currentTime()+"ACK"+n+" sent, expecting packet"+ ++n);
		expectedSeq = n;
	}
	public static int packetCounter = 0;
	public static int expectedSeq = 0;
	public static boolean isDiscard = false;
}